package com.reformer.commons.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
@Slf4j
public class SignUtils {

    //签名参数名称
    public static final String param_signature = "sign";
    // 算法常量： SHA256
    private static final String ALGORITHM_SHA256 = "SHA-256";


    /**
     * 将Map中的数据转换成key1=value1&key2=value2的形式 不包含签名域signature
     *
     * @param data 待拼接的Map数据
     * @return 拼接好后的字符串
     */
    public static String coverMap2String(Map<String, String> data) {
        TreeMap<String, String> tree = new TreeMap<String, String>();
        Iterator<Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            if (param_signature.equals(en.getKey().trim())) {
                continue;
            }
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer();
        while (it.hasNext()) {
            Entry<String, String> en = it.next();
            sf.append(en.getKey() + "=" + en.getValue() + "&");
        }
        return sf.substring(0, sf.length() - 1);
    }

    /**
     * 将map集合按字母大小排序后加密
     *
     * @param data      加密集合
     * @param key       签名key
     * @param key       密钥
     * @param encoding  编码值
     * @return
     */
    public static String signBySecureKey(Map<String, String> data, String key, String encoding) {
        // 将Map信息转换成key1=value1&key2=value2的形式
        String stringData = coverMap2String(data);
        String strBeforeSha256 = stringData + "&" + sha256X16Str(key, encoding);
        String strAfterSha256 = sha256X16Str(strBeforeSha256, encoding);
        return strAfterSha256;
    }


    /**
     * 过滤请求报文中的空字符串或者空字符串
     *
     * @param contentData
     * @return
     */
    public static Map<String, String> filterBlank(Map<String, String> contentData) {
        Map<String, String> submitFromData = new HashMap<String, String>();
        Set<String> keyset = contentData.keySet();
        for (String key : keyset) {
            String value = contentData.get(key);
            if (!isBlank(value)) {
                // 对value值进行去除前后空处理
                submitFromData.put(key, value.trim());
            }
        }
        return submitFromData;
    }


    /**
     * 验证签名(SHA256算法)<br>
     *
     * @param rspData  返回报文数据<br>
     * @param key      签名key<br>
     * @param encoding 上送请求报文域encoding字段的值<br>
     * @return true 通过 false 未通过<br>
     */
    public static boolean validateBySha256(Map<String, String> rspData, String key, String encoding) {
        rspData = filterBlank(rspData);
        String stringSign = rspData.get(param_signature);
        if (stringSign == null || stringSign.length() == 0) {
            return false;
        }
        String stringData = coverMap2String(rspData);
        String strBeforeSha256 = stringData + "&" + sha256X16Str(key, encoding);
        String strAfterSha256 = sha256X16Str(strBeforeSha256, encoding);
        return stringSign.equals(strAfterSha256);
    }

    /**
     * sha256计算后进行16进制转换
     *
     * @param data     待计算的数据
     * @param encoding 编码
     * @return 计算结果
     */
    public static String sha256X16Str(String data, String encoding) {
        byte[] bytes = sha256(data, encoding);
        StringBuilder sha256StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sha256StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));
            } else {
                sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sha256StrBuff.toString();
    }

    /**
     * sha256计算
     *
     * @param datas    待计算的数据
     * @param encoding 字符集编码
     * @return
     */
    private static byte[] sha256(String datas, String encoding) {
        try {
            return sha256(datas.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            log.error(e.toString(), e);
            return null;
        }
    }

    /**
     * sha256计算.
     *
     * @param data 待计算的数据
     * @return 计算结果
     */
    private static byte[] sha256(byte[] data) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance(ALGORITHM_SHA256);
            md.reset();
            md.update(data);
            return md.digest();
        } catch (Exception e) {
            log.error(e.toString(), e);
            return null;
        }
    }


    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }


}
